﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using X3DXNA.interfaces;
using X3DXNA.X3DSchema;
using X3DXNA.basicModels;
using Microsoft.Xna.Framework;
using X3DXNA.utils;
using X3DXNA.debug;
using X3DXNA.core.CustomNodes;

namespace X3DXNA.core.Controllers
{
    class GeometryController
    {
        List<IUsable> geometries;
        Debug debugSystem;

        public GeometryController(Debug debugSystem)
        {
            geometries = new List<IUsable>();
            this.debugSystem = debugSystem;
        }

        public IGeometry handleGeometry(Shape shape, Game game, MyTransform transformation, MyAppearance myAppearance)
        {
            IGeometry geometryToReturn = null;

            if (shape != null && shape.USE == null)
            {
                foreach (INode node in shape.Childs)
                {
                    if (node is Box)
                    {
                        //geometryToReturn = basicBox.getNewBasicBox(game, (Box)node, transformation.getMatrixTransformation, transformation.IsRouted);
                        geometryToReturn = basicBoxModel.getNewBasicBoxModel(game, (Box)node, transformation.getMatrixTransformation);
                    }
                    else if (node is Cone)
                        geometryToReturn = basicConeModel.getNewBasicConeModel(game, (Cone)node, transformation.getMatrixTransformation);
                    else if (node is Sphere)
                        //geometryToReturn = new basicSphere(game, node.DEF, utility.stringToFloat(((Sphere)node).radius), transformation.getMatrixTransformation);
                        geometryToReturn = basicSphereModel.getNewBasicSphereModel(game, (Sphere)node, transformation.getMatrixTransformation);
                    else if (node is Cylinder)
                        //geometryToReturn = new basicCylinder(game, node.DEF, utility.stringToFloat(((Cylinder)node).radius), utility.stringToFloat(((Cylinder)node).height), transformation.getMatrixTransformation);
                        geometryToReturn = basicCylinderModel.getNewBasicCylinderModel(game, (Cylinder)node, transformation.getMatrixTransformation);
                    else if (node is IndexedFaceSet)
                        geometryToReturn = handleIndexedFaceSet(game, (IndexedFaceSet)node, transformation.getMatrixTransformation);
                    else if (node is IndexedTriangleSet)
                        geometryToReturn = handleIndexedTriangleSet(game, (IndexedTriangleSet)node, transformation.getMatrixTransformation);

                    #warning Aggiungere altre geometrie di base.
                }
                if (geometryToReturn != null)
                    geometries.Add(geometryToReturn);
            }
            else if (shape.USE != null)
            {
                geometryToReturn = (IGeometry)utility.findUsable(geometries, shape.USE);

                if (geometryToReturn == null)
                {
                    debugSystem.addMessage("Attenzione, utilizzo di USE improprio: Non è stata trovato alcuna Geometria definita con il tag DEF = " + shape.USE, typeof(GeometryController));
                }
            }

            return geometryToReturn;
        }

        private basicIndexedFaceSet handleIndexedFaceSet(Game game, IndexedFaceSet ifs, Matrix transformation)
        {
            Int16[] indices = utility.stringToIndicesIndexedFaceSet(ifs.coordIndex);
            Vector3[] vertices = null;
            Vector3[] normals = null;

            foreach (INode child in ifs.Childs)
            {
                if (child is Coordinate)
                {
                    vertices = utility.stringToVertices(((Coordinate)child).point);
                }
                else if (child is Normal)
                {
                    normals = utility.stringToVertices(((Normal)child).vector);
                }
            }

            if (indices == null || vertices == null)
                return null;
            else
                return new basicIndexedFaceSet(game, ifs.DEF, indices, vertices,normals, transformation);
        }

        private basicIndexedTriangleSet handleIndexedTriangleSet(Game game, IndexedTriangleSet its, Matrix transformation)
        {
            Int16[] indices = utility.stringToIndices(its.index);
            Vector3[] vertices = null;
            Vector3[] normals = null;

            foreach (INode child in its.Childs)
            {
                if (child is Coordinate)
                {
                    vertices = utility.stringToVertices(((Coordinate)child).point);
                }
                else if (child is Normal)
                {
                    normals = utility.stringToVertices(((Normal)child).vector);
                }
            }

            if (indices == null || vertices == null)
                return null;

            else
                return new basicIndexedTriangleSet(game, its.DEF, indices, vertices, normals, transformation);
        }
    }
}
